#/usr/bin/env python

import pygame
from pygame.locals import *
import random
import time, sys
from gloss import *

from CardImages import CardImagesGL
from CardGroup import CardGroupGL
from Card import CardGL
from NetPackets import *
from pygamenet import *

connection = None

use_network = False

class DeckOfCards(GlossGame):

    def __init__(self, observer):
        self.observer = observer
        self.backgroundImage = None
        GlossGame.__init__(self, "Game")

    NOTHING = 0
    DRAW_SELECTION = 1
    CARD_SELECTED = 2
    SELECTION_SELECTED = 3
    SELECTION_SPREAD_INIT = 4
    SELECTION_SPREAD = 5

    LEFT = 0
    RIGHT = 1
    TOP = 2
    BOTTOM = 3

    HORISONTAL = 0
    VERTICAL = 1

    MAX_HISTORY = 30
    m_history = []

    def clearHistory(self):
        self.m_history = []

    def pushHistory(self, desc):
        print "Pushing: %s" % desc
        while len(self.m_history) > self.MAX_HISTORY:
            self.m_history.pop(0)

        # store get the z-order
        cards = self.m_cardGroup.m_cards[:]

        # store card info
        cardinfo = []
        for c in cards:
            cardinfo.append(c.getInfo())

        if len(self.m_selectionCards):
            selrect = pygame.Rect(self.m_selectionRect)
            selcards = self.m_selectionCards[:]
        else:
            selrect = pygame.Rect((0, 0, 0, 0))
            selcards = []

        self.m_history.append([cards, cardinfo, selrect, selcards, desc])

    def popHistory(self):
        if not len(self.m_history):
            return

        history = self.m_history.pop()

        print "Popping: %s" % history[4]

        cards = history[0]

        i = 0
        for ci in history[1]:
            cards[i].setInfo(ci)
            i += 1

        self.m_cardGroup.m_cards = cards
        self.m_selectionRect = history[2]
        self.m_selectionCards = history[3]

    def setBackground(self, filename):
        pass
#        image = pygame.image.load("./backgrounds/"+filename)
#        image = pygame.transform.smoothscale(image, (self.m_screen.get_rect().width, self.m_screen.get_rect().height))
        self.backgroundImage = Texture("./backgrounds/"+filename)

    def updateSelectionRect(self):
        rectangle = None
        for c in self.m_selectionCards:
            if not rectangle:
                rectangle = pygame.Rect(c.rect)
            else:
                rectangle.union_ip(c.rect)
        rectangle.x -= 3
        rectangle.y -= 3
        rectangle.width += 6
        rectangle.height += 6

        self.m_selectionRect = rectangle

    def shuffleSelection(self):
        if len(self.m_selectionCards):
            rectbuf = []
            for c in self.m_selectionCards:
                rectbuf.append(pygame.Rect(c.rect))

            random.shuffle(self.m_selectionCards)

            for i in range(len(rectbuf)):
                self.m_selectionCards[i].rect = rectbuf[i]

            self.m_cardGroup.popCards(self.m_selectionCards)
            
    def alignSelectionGeneric(self, lget, lset):
        left = lget(self.m_selectionCards[0].rect)
        for c in self.m_selectionCards:
            if lget(c.rect) < left:
                left = lget(c.rect)
        for c in self.m_selectionCards:
            lset(c.rect, left)
        self.updateSelectionRect()

    def alignSelection(self, direction):
        self.pushHistory("Align")
        if len(self.m_selectionCards):
            if direction == self.LEFT:
                self.alignSelectionGeneric(lambda e: e.left, 
                                       lambda e, v: setattr(e, "left", v))
            elif direction == self.RIGHT:
                self.alignSelectionGeneric(lambda e: e.right, 
                                       lambda e, v: setattr(e, "right", v))
            elif direction == self.TOP:
                self.alignSelectionGeneric(lambda e: e.top, 
                                       lambda e, v: setattr(e, "top", v))
            elif direction == self.BOTTOM:
                self.alignSelectionGeneric(lambda e: e.bottom, 
                                       lambda e, v: setattr(e, "bottom", v))

    def distributeSelection(self, direction):
        self.pushHistory("Distribute")
        if len(self.m_selectionCards):
            if direction == self.HORISONTAL:
                # Sort cards by rect.left
                self.m_selectionCards.sort(lambda x, y: x.rect.left-y.rect.left)
                # MostLeft card
                mostleft = self.m_selectionCards[0].rect.left
                for c in self.m_selectionCards:
                    c.rect.left = mostleft
                    mostleft += 50
            elif direction == self.VERTICAL:
                # Sort cards by rect.left
                self.m_selectionCards.sort(lambda x, y: x.rect.top-y.rect.top)
                # MostLeft card
                mosttop = self.m_selectionCards[0].rect.top
                for c in self.m_selectionCards:
                    c.rect.top = mosttop
                    mosttop += 50
            self.updateSelectionRect()
            
    def drawDeck(self):
        global connection
        # Init deck
#        cards = []
        for i in range(0, 52):
#            cards.append(Card(self.cardImages.getCardNbr(i), self.cardImages.getBack(), 30, 30))
            self.m_cardGroup.addCard(CardGL(self.cardImages.getCardNbr(i), self.cardImages.getBack(), 30, 30, i, connection))
#            self.m_cardGroup.addCard(Card(self.cardImages.getCardNbr(i), self.cardImages.getBack(), 30, 30, i, None))

        #second deck
        #for i in range(0,52):
        #    m_cards.append(Card(ci.getCardNbr(i),ci.getBack(),15,15))

    def load_content(self):
        print "Loading resources"
        global connection
#        pygame.init()

        if use_network:
            connection = Client()
            connection.connect('127.0.0.1', 9123)

        # Auth and get version
#            sentPacket("COMMAND_LOGIN", ("user", "passwd"), connection)
            not_connected = True
            while not_connected:
                for msg in connection.get():
                    print str(msg)
                    if msg.type == 'server_ready':
                        not_connected = False

            connection.send(Message('request_board_state'))

#        self.m_screen = pygame.display.set_mode((800, 600), HWSURFACE | RESIZABLE)
#        pygame.display.set_caption('CCGCarpet - v1.0')
        self.m_selectedCard = None

        self.m_console = False

        self.m_selectionRect = pygame.Rect((0, 0, 0, 0))
        self.m_selectionCards = []

        self.cardImages = CardImagesGL()

        cards = []
        self.m_cardGroup = CardGroupGL(cards)

        if not self.observer:
            self.drawDeck()
            self.m_cardGroup.shuffle()

        self.m_mode = self.NOTHING

        popsingle = 0

        self.backgroundImageFilename = "1235594258_ss_vintage_floral_background.jpg"
        self.setBackground(self.backgroundImageFilename)

        self.m_helptext = pygame.Surface((380, 420), 1).convert()
        self.m_helptext.fill((0x0, 0x0, 0x0))
        self.m_helptext.set_alpha(200);
        self.m_helptextRect = self.m_helptext.get_rect()

#        font = pygame.font.Font("FreeSans.ttf", 18)
#        ty = 8
#        for t in self.help_text:
#            img = font.render(t, 1, (0xff, 0xff, 0))
#            r = img.get_rect()
#            r.top = ty
#            r.centerx = self.m_helptextRect.centerx
#            ty += 25
#            self.m_helptext.blit(img, r.topleft)

        self.viewhelp = 1
        sr = self.get_rect()
        self.m_helptextRect.centerx = sr.centerx
        self.m_helptextRect.centery = sr.centery

        self.lctrlDown = 0
        self.rctrlDown = 0
        self.lshiftDown = 0
        self.rshiftDown = 0

        self.on_mouse_up = self.handle_mouse_up
        self.on_mouse_down = self.handle_mouse_down
        self.on_mouse_motion = self.handle_mouse_motion
        self.on_nonhandled_events = self.handle_nonhandled_events
        self.on_key_down = self.handle_key_down
        self.on_key_up = self.handle_key_up

    def get_rect(self):
        rect = Rect(0, 0, Gloss.screen_resolution[0], Gloss.screen_resolution[1])
        return rect

    def draw(self):
        self.mainLoop()

    def handle_mouse_down(self, event):
#        print event
        if self.m_mode == self.NOTHING and (event.button in [1, 2, 3]):
            #Check if we are inside selection.
            if self.m_selectionRect.width > 0 and self.m_selectionRect.height > 0:
                if self.m_selectionRect.collidepoint(event.pos[0], event.pos[1]):
                    if self.lshiftDown or self.rshiftDown:

                        if len(self.m_selectionCards) >= 2:
                            self.pushHistory("Collecting/spreading selection")

                            cx = self.m_selectionCards[0].rect.centerx
                            cy = self.m_selectionCards[0].rect.centery
                            for c in self.m_selectionCards:
                                c.rect.centerx = cx
                                c.rect.centery = cy
                            self.updateSelectionRect()

                            if event.button == 3:
                                self.m_selectionCards.reverse()
                                for c in self.m_selectionCards:
                                    c.flip()
                            self.m_cardGroup.popCards(self.m_selectionCards)

                            pygame.mouse.set_pos((cx, cy))
                            self.m_mode = self.SELECTION_SPREAD_INIT
                    else:
                        self.pushHistory("Pop/flip selection")
                        self.m_mode = self.SELECTION_SELECTED
                        if event.button == 3:
                            self.m_selectionCards.reverse()
                            for c in self.m_selectionCards:
                                c.flip()
                        self.m_cardGroup.popCards(self.m_selectionCards)

            if self.m_mode == self.NOTHING:
                if len(self.m_selectionCards):
                    self.pushHistory("Drop selection m_cards")
                    self.m_cardGroup.popCards(self.m_selectionCards)
                    self.m_cardGroup.dropCards(self.m_selectionCards)
                    self.m_selectionCards = []
                    self.m_selectionRect.size = (0, 0)

            #Check if any card is selected.
            if self.m_mode == self.NOTHING:
#                pop = popsingle
                # For single select
#                            if event.button == 2:
#                                popsingle = 1
                self.pushHistory("Pop/flip selected card")
                self.m_selectedCard = self.m_cardGroup.getCard(event.pos[0], event.pos[1], 0)
                # For single select
#                            if event.button == 2:
#                                popsingle = pop
                if self.m_selectedCard:
                    self.m_mode = self.CARD_SELECTED
                    if event.button == 2:
                        self.m_selectedCard.turn()
                    if event.button == 3:
                        self.m_selectedCard.flip()
                else:
                    self.m_history.pop()
            #Init a new selection rectangle.
            if self.m_mode == self.NOTHING:
                self.selectionStart = (event.pos[0], event.pos[1])
                self.m_mode = self.DRAW_SELECTION

    def handle_mouse_up(self, event):
#        print event
        if self.m_mode == self.SELECTION_SELECTED:
            self.m_mode = self.NOTHING

        elif self.m_mode == self.SELECTION_SPREAD:
            self.m_mode = self.NOTHING

        elif self.m_mode == self.SELECTION_SPREAD_INIT:
            self.m_mode = self.NOTHING

        elif self.m_mode == self.CARD_SELECTED:
            #self.pushHistory("Drop card")
            self.m_cardGroup.dropCard(self.m_selectedCard)
            self.m_selectedCard = None
            self.m_mode = self.NOTHING

        elif self.m_mode == self.DRAW_SELECTION:
            #see if we have selected any m_cards
            if self.m_selectionRect.width > 0 and self.m_selectionRect.height > 0:
                self.pushHistory("Select m_cards")
                self.m_selectionRect, self.m_selectionCards = self.m_cardGroup.getCards(self.m_selectionRect)
                if not len(self.m_selectionCards):
                    self.m_history.pop()
            self.m_mode = self.NOTHING

    def handle_mouse_motion(self, event):
#        print event
        if event.buttons[0] or event.buttons[1] or event.buttons[2]:
            if self.m_mode == self.SELECTION_SELECTED:
                # Handle the drag of a selection rectangle.
                if len(self.m_selectionCards):
                    self.m_selectionRect.topleft = (self.m_selectionRect.x + event.rel[0], self.m_selectionRect.y + event.rel[1])
                    for c in self.m_selectionCards:
                        c.move(event.rel[0], event.rel[1]);

            elif self.m_mode == self.SELECTION_SPREAD_INIT:
                self.m_mode = self.SELECTION_SPREAD

            elif self.m_mode == self.SELECTION_SPREAD:
                # Handle the spread of a selection rectangle.
                l = len(self.m_selectionCards)
                if l >= 2:

                    c = self.m_selectionCards[l - 1]
                    fc = self.m_selectionCards[0]

                    dx = event.pos[0] - fc.rect.centerx
                    dy = event.pos[1] - fc.rect.centery

                    if abs(dx) > abs(dy):
                        cnt = 0
                        d = float(dx) / float(l - 1)
                        for mc in self.m_selectionCards:
                            mc.rect.centery = fc.rect.centery
                            mc.rect.centerx = fc.rect.centerx + int(d * cnt)
                            cnt += 1
                        c.rect.centerx = event.pos[0]
                        c.rect.centery = fc.rect.centery
                    else:
                        cnt = 0
                        d = float(dy) / float(l - 1)
                        for mc in self.m_selectionCards:
                            mc.rect.centerx = fc.rect.centerx
                            mc.rect.centery = fc.rect.centery + int(d * cnt)
                            cnt += 1
                        c.rect.centery = event.pos[1]
                        c.rect.centerx = fc.rect.centerx

                    r = pygame.Rect(c.rect)
                    r.union_ip(self.m_selectionCards[0].rect)
                    r.x -= 3
                    r.y -= 3
                    r.width += 6
                    r.height += 6
                    self.m_selectionRect = r

            elif self.m_mode == self.CARD_SELECTED:
                # Handle the drag of a selected card.
                self.m_selectedCard.move(event.rel[0], event.rel[1]);

            elif self.m_mode == self.DRAW_SELECTION:
                # Handle the selection rectangle
                #self.m_selectionRect.size=(event.pos[0]-self.m_selectionRect.x,event.pos[1]-self.m_selectionRect.y)

                if event.pos[0] <= self.selectionStart[0]:
                    self.m_selectionRect.x = self.selectionStart[0] - (self.selectionStart[0] - event.pos[0])
                    self.m_selectionRect.width = self.selectionStart[0] - event.pos[0]
                else:
                    self.m_selectionRect.x = self.selectionStart[0]
                    self.m_selectionRect.width = event.pos[0] - self.selectionStart[0]

                if event.pos[1] <= self.selectionStart[1]:
                    self.m_selectionRect.y = self.selectionStart[1] - (self.selectionStart[1] - event.pos[1])
                    self.m_selectionRect.height = self.selectionStart[1] - event.pos[1]
                else:
                    self.m_selectionRect.y = self.selectionStart[1]
                    self.m_selectionRect.height = event.pos[1] - self.selectionStart[1]
        else:
            if self.m_mode == self.NOTHING:
                card = self.m_cardGroup.getCardWithoutTossing(event.pos[0], event.pos[1])
                if card:
                    card.setHighlight(True)

    def handle_nonhandled_events(self, event):
        pass
#        print event

    def handle_key_down(self, event):
        print event
        #print "key = %s" % str(event.key)
        #print "keyname = %s" % pygame.key.name(event.key)
#        if viewhelp:
#            if event.key == K_ESCAPE:
#                return
#            viewhelp = 0
#            continue
        if event.key == K_ESCAPE:
            # Return from dev console
            if self.m_console:
                self.m_console = False
        elif event.key == K_EURO:
            self.m_console = not self.m_console
            print "!!!!!!!!!!!!!!!!!!!!111-1"
            pass
        elif event.key == K_FIRST or K_GREATER or K_EXCLAIM:
            print "!!!!!!!!!!!!!!!!!!!!111-2"
            pass
        elif event.key == K_HASH or K_LEFTBRACKET or K_LEFTPAREN or K_LESS:
            print "!!!!!!!!!!!!!!!!!!!!222"
            pass
        elif event.key == K_LMETA or K_PERIOD or K_QUESTION or K_QUOTE or K_QUOTEDBL:
            print "!!!!!!!!!!!!!!!!!!!!333"
            pass
            self.lctrlDown = 1
        elif event.key == K_LCTRL:
            self.lctrlDown = 1
        elif event.key == K_RCTRL:
            self.rctrlDown = 1
        elif event.key == K_LSHIFT:
            self.lshiftDown = 1
        elif event.key == K_RSHIFT:
            self.rshiftDown = 1
        elif event.key == 122 and (self.lctrlDown or self.rctrlDown):
            self.popHistory()
        elif event.key == 116 and (self.lctrlDown or self.rctrlDown):
            if popsingle:
                popsingle = 0
            else:
                popsingle = 1
        elif event.key == 115 and (self.lctrlDown or self.rctrlDown):
            self.pushHistory("Selection shuffle")
            self.shuffleSelection()
        elif event.key == K_F1:
            if self.m_mode == self.NOTHING:
                sr = self.m_screen.get_rect()
                self.m_helptextRect.centerx = sr.centerx
                self.m_helptextRect.centery = sr.centery
                viewhelp = 1
        elif event.key == K_F2:
            self.pushHistory("F2")
            self.m_selectionRect = pygame.Rect((0, 0, 0, 0))
            self.m_selectionCards = []
            self.m_cardGroup.collectAll(30, 30)
            self.m_cardGroup.shuffle()
        elif event.key == K_F3:
            self.pushHistory("Setup Klondike")
            self.initKlondike()
        # Align
        elif event.key == K_LEFT:
            self.alignSelection(self.LEFT)
        elif event.key == K_RIGHT:
            self.alignSelection(self.RIGHT)
        elif event.key == K_UP:
            self.alignSelection(self.TOP)
        elif event.key == K_DOWN:
            self.alignSelection(self.BOTTOM)
        # Distribute
        elif event.key == K_h:
            self.distributeSelection(self.HORISONTAL)
        elif event.key == K_v:
            self.distributeSelection(self.VERTICAL)
        else:
            self.chat_handle(event.unicode)

    def chat_handle(self, char):
        print char

    def handle_key_up(self, event):
        print event
        if event.key == K_LCTRL:
            self.lctrlDown = 0
        elif event.key == K_RCTRL:
            self.rctrlDown = 0
        elif event.key == K_LSHIFT:
            self.lshiftDown = 0
        elif event.key == K_RSHIFT:
            self.rshiftDown = 0

    def mainLoop(self):
        global connection

        if True:
            # Network events
            if use_network:
                for msg in connection.get():
                    print msg
                    if msg.type == COMMAND_CARD_ADD:
                        id, pos_x, pos_y = msg
                        self.m_cardGroup.addCard(Card(self.cardImages.getCardNbr(id), self.cardImages.getBack(), pos_x, pos_y, id))
                    if msg.type == COMMAND_CARD_MOVE:
                        id, pos_x, pos_y = msg
                        self.m_cardGroup.getCardById(id).move_abs(pos_x, pos_y)
                    if msg.type == COMMAND_CARD_ROTATE:
                        id, flag = msg
                        self.m_cardGroup.getCardById(id).setTurn(bool(flag))
                    if msg.type == COMMAND_CARD_FLIP:
                        id, flag = msg
                        self.m_cardGroup.getCardById(id).setSide(bool(flag))


            # Pygame events
#            for event in pygame.event.get():
            while False:
                if event.type == QUIT:
#                    connection.send_object('quit')
#                    client.shutdown()
                    return
                elif event.type == VIDEORESIZE:
                    self.m_screen = pygame.display.set_mode(event.size, HWSURFACE | RESIZABLE)
                    self.setBackground(self.backgroundImageFilename)
                    if viewhelp:
                        sr = self.m_screen.get_rect()
                        self.m_helptextRect.centerx = sr.centerx
                        self.m_helptextRect.centery = sr.centery

            # DRAWING             
#            self.m_screen.fill((0x00, 0xb0, 0x00))
            Gloss.clear(Color.GREEN)

            if self.backgroundImage:
                Gloss.fill(self.backgroundImage)

#                self.m_screen.blit(self.backgroundImage, self.backgroundImage.get_rect().topleft)
#                self.backgroundImage.draw(position=(0,0), origin=(0,0))

            self.m_cardGroup.draw()

            if self.m_selectionRect.width > 0 and self.m_selectionRect.height > 0:
#                Gloss.draw_box((self.m_selectionRect.left, self.m_selectionRect.top), self.m_selectionRect.width, self.m_selectionRect.height)

                Gloss.draw_line((self.m_selectionRect.left, self.m_selectionRect.top), (self.m_selectionRect.right, self.m_selectionRect.top))
                Gloss.draw_line((self.m_selectionRect.right, self.m_selectionRect.top), (self.m_selectionRect.right, self.m_selectionRect.bottom))
                Gloss.draw_line((self.m_selectionRect.right, self.m_selectionRect.bottom), (self.m_selectionRect.left, self.m_selectionRect.bottom))
                Gloss.draw_line((self.m_selectionRect.left, self.m_selectionRect.bottom), (self.m_selectionRect.left, self.m_selectionRect.top))
#                pygame.draw.rect( (0xff, 0xff, 0x00), self.m_selectionRect, 3)

            if self.m_console:
                Gloss.set_scene_tint(Color.RED)
            else:
                Gloss.set_scene_tint(Color.WHITE)

#            if viewhelp:
#                self.m_screen.blit(self.m_helptext, self.m_helptextRect.topleft)

#            pygame.display.flip()

#        client.shutdown()


def main(observer=False):
    g = DeckOfCards(observer)
#    g.mainLoop()
    g.run()


#this calls the 'main' function when this script is executed
if __name__ == '__main__':
    if len(sys.argv) > 1:
        main(True)
    else:
        main(False)

